Retrofit是一個強大、方便的工具,可以讓開發人員更容易地執行網絡請求並處理 API 數據,並且它還可以結合其他的套件一起使用,使其的功能可以變得更加強大,也因為它簡單好上手,所以也很適合拿來給初新者使用
這次會使用網路上提供的假資料,網址是https://jsonplaceholder.typicode.com/albums
。
dependencies
,也因為其性質是要向網路請求抓取API資料,所以也要開啟網路請求的功能。使用Retrofit需要先加入必要的dependencies
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
加入完後,上面會跳出這串
點選Sync Now
再讓他跑一下就可以了。
網路請求要在AndroidManifest.xml
進行,在application
上方加上
<uses-permission android:name="android.permission.INTERNET" />
就像上面展示的一樣,到此就完成了Retrofit的前置作業。
雖然Retrofit的環境建立寫在MainActivity裡面也是可以,但是這邊推薦將環境建立寫在外面,這麼做最大的好處就是可以讓所有需要使用到Api的Activity都可以調用,就不需要每次都寫一次重複的架構,下面就開始講解:
首先要先建立一個Class
,這邊我取名為ApiClient
,接著就開始寫Retrofit的環境
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class ApiClient {
public Retrofit testWebData(){
return new Retrofit.Builder()//建立Retrofit
.baseUrl("https://jsonplaceholder.typicode.com/")
//輸入Api資料網站
.addConverterFactory(GsonConverterFactory.create())
//添加Gson轉換器,這個幫助我們將http上的資料轉成Retrofit能夠處理的Json數據並將其轉換為Java對象
.build();
//將環境建立起來
}
}
可以看到,這裡建立了一個方法,用來回傳建立好的Retrofit環境,後面要使用到這個Api的Activity就可以呼叫ApiClient裡面的testWebData再create就好。
建立一個class叫DataResponse用來接收資料
public class DataResponse {
private int userId;
private int id;
private String title;
@Override
public String toString() {
return "DataResponse{" +
"\nuserId=" + userId +
",\n id=" + id +
",\n title='" + title + '\'' +
'}';
}
public int getUserId() {
return userId;
}
public int getId() {
return id;
}
public String getTitle() {
return title;
}
}
這邊要宣告Api資料裡面,需要取得的資料的資料型態,例如:id是int型態,那就要宣告為int。
這裡要注意!不只型態要對,資料的名字也一定要對,否則你資料不管如何都一定抓不到,資料宣告有兩種方式,正式一點的就是寫成private,想要方便一點的就是用public,兩者的差別在於,前者要用getter和setter,後者則可以直接調用。
可以看到這個部分
private int userId;
private int id;
private String title;
我是宣告為private
,且所有的資料都是符合Api資料的型態跟名字
下面則可以看到我重新撰寫了一個自己的toString()
,關於這個我推薦使用內建的方式撰寫,會比自己寫得更加快速,後續再根據自己的需求改變部分的樣式就好,使用方法入下:
依序從左到右,先點擊右鍵後選擇Generate
> toString()
> 最後將要打包在toString的資料選好在按OK
,這樣就會自動生成自己的toString囉~
建立toString是為了要將取得的資料一次顯示,但是如果今天我只是需要其中的一個資料要怎麼做呢?
接著往下看到這裡
public int getUserId() {
return userId;
}
public int getId() {
return id;
}
public String getTitle() {
return title;
}
這個部分就是getter
,也就是給外面要取資料用的,有了這個方法外面就可以指定要哪一個資料,建立方法我一樣推薦使用內建的Generate
來生成,步驟如下:
依序從左到右,先點擊右鍵後選擇Generate
> Getter
> 最後選完要使用Getter再按下OK
,就建立好Getter囉~
建立ineterface的方法跟class再同個地方
只要點選下面的interface就可以建立了,這邊我命名為GetApi
public interface GetApi {
@GET("albums/{id}")
//在/後面加上id可以查到那個id的資料
Call<DataResponse> getJsonData(@Path("id") int id);
//用Path將傳入的id填入{}裡面
}
一個interface裡面可以放入多個請求api的方法,新增的方式就像上面這樣
使用@Get
請求資料,()後放的是網址以及參數
再來使用Call
去呼叫,<>
裡面放入你創建的接收資料的class
然後命名,後面@Path
是為了將參數填到上面{}裡面,這邊也要記得資料的形態要正確。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.5"
android:gravity="center"
android:textSize="30sp"
android:textStyle="bold"
android:background="@drawable/border"
android:text="TextView" />
<EditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="0.2"
android:ems="10"
android:inputType="text"
android:textSize="35sp"
android:gravity="center"
android:background="@drawable/border"
android:hint="輸入數字(1~100)"/>
<Button
android:id="@+id/button"
android:layout_width="300dp"
android:layout_height="0dp"
android:layout_weight="0.3"
android:textSize="40sp"
android:background="@drawable/border"
android:text="查詢" />
</LinearLayout>
由於這個Api資料可以透過搜尋id的方式來抓取不同的資料,所以這次的設計就加上了EditText跟Button,做到搜尋的功能。
private TextView textView;
private Button button;
private EditText editText;
private ApiClient apiClient;
private GetApi getApi;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.textView);
button = findViewById(R.id.button);
editText = findViewById(R.id.editText);
apiClient = new ApiClient();
getApi = apiClient.testWebData().create(GetApi.class);
button.setOnClickListener(view -> {
Call call = getApi.getJsonData(Integer.parseInt(editText.getText().toString()));
call.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
textView.setText(response.body().toString());
}
@Override
public void onFailure(Call call, Throwable t) {
textView.setText("資料抓取失敗");
}
});
});
}
首先要宣告ApiClient、GetApi
private ApiClient apiClient;
private GetApi getApi;
接著進行初始化跟綁定
apiClient = new ApiClient();
getApi = apiClient.testWebData().create(GetApi.class);
以上就已經成功創立一個Retrofit的環境
接著就是開始抓取Api的資料,這邊我寫在Button的點擊事件內,概念是點擊搜尋後,就將EditText內輸入的資料丟給Retrofit,讓它依照這個參數去尋找我想要的資料
button.setOnClickListener(view -> {
Call call = getApi.getJsonData(Integer.parseInt(editText.getText().toString()));
call.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
textView.setText(response.body().toString());
}
@Override
public void onFailure(Call call, Throwable t) {
textView.setText("資料抓取失敗");
}
});
});
首先看到這個部分
Call call = getApi.getJsonData(Integer.parseInt(editText.getText().toString()));
這裡創建了一個Call,同時呼叫了getApi裡面的getJsonData並且向裡面傳入了EditText輸入的內容
再來這個部分
call.enqueue(new Callback() {
@Override
public void onResponse(Call call, Response response) {
textView.setText(response.body().toString());
}
@Override
public void onFailure(Call call, Throwable t) {
textView.setText("資料抓取失敗");
}
});
這裡使用的是Retrofit的異步執行請求,使用enqueue
可以將要取Api資料的動作切換到背景執行,並在請求完後調用Callback的方法
接著就會得到下面兩個方法onResponse
、onFailure
,分別代表得到資料後做的事,還有資料抓取失敗時要做的事
因此我在抓到資料的地方設定TextView填入抓取到的資料,讀取資料的方法要用到response.body()
,後面接到在DataResponse裡面寫到的方法
,失敗的部分就將TextView填入資料抓取失敗
的字串。
RxJava
,RxJava在使用上比較方便,切換theard的方法也更加清楚,是個很常會用來跟Retrofit結合的套件。